import traceback

from model.model import Request_data, DocDataObj, ComparisonData, Item_data
from func_timeout import func_set_timeout
from pdf2docx import Converter

from mongoDBUtil import MongoDBUtil
from utils import *
import datetime
from typing import List
# from win32com import client as wc
# import pythoncom

import gc

# 生成html文件根目录
# html_file_save_path = "/work/project/bid-analyzer/files/docdiff/html/"
# html_file_save_path = "html/"
# log_path = "/work/project/bid-analyzer-node/files/docdiff/log/"
log_path = "log/"
html_content = '<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><title>%s</title><style>body,select,textarea {font-size:0.8em}body, html,input{font-family:"微软雅黑";}body{width:600px;margin-left:10px;}span{ margin:8px 0;}</style></head><body style=\"display: flex;justify-content: center;flex-direction: column;\">'
mongodb_obj = MongoDBUtil()


# 对比相似度
def similarity_cont(request_data: Request_data):
    if request_data:
        if not request_data.file_paths:
            return {'msg': '文件不能为空', 'code': 500}
        start = datetime.datetime.now()

        # 操作模板文件
        template_path_list, template_error_file_path = to_docx(request_data.templatePath, "template")
        # 获取模板文件的内容列表
        template_str_list, error_files = read_template_list(template_path_list)
        error_log()
        file_list, diff_error_file_path = to_docx(request_data.file_paths, "diff")

        # 模板过滤
        # 1.转入模板内容和对比文件列表对象
        # 2.对比文件内容与模板内容做相似度对比,得到每一个对比文件最后过滤的内容
        # 3.添加到文件列表对象中返回
        # 模板文件过滤
        write_log(" 正在进行模板内容过滤---\n")
        file_data, not_contents = template_filter(template_str_list, file_list)
        # 如果是一个文件或者无文件无法对比
        if len(file_data) == 1 or len(file_data) == 0:
            comparison_data = ComparisonData()
            comparison_data.code = 200
            comparison_data.totalNumber = -1
            comparison_data.encryption_broken_list = error_files + not_contents
            return comparison_data

        result_data, total_number = similar_juxtapose(file_data)

        # 生成html页面报告
        html_paths = detail_report(result_data, file_list)

        comparison_data = ComparisonData()
        comparison_data.totalNumber = total_number
        comparison_data.towFileData = result_data
        comparison_data.error_file_path = template_error_file_path + diff_error_file_path
        comparison_data.encryption_broken_list = error_files + not_contents
        comparison_data.html_paths = html_paths
        comparison_data.code = 200
        comparison_data.msg = "操作成功"
        write_log(" 文件对比完成,消耗时间: " + str(
            (datetime.datetime.now() - start).seconds) + "秒\n文件对比结束,准备生成报告结果 --\n")
        if template_str_list:
            del template_str_list
            gc.collect()
        if file_list:
            del file_list
            gc.collect()

        return comparison_data
    else:
        return {"code": 500, "msg": "数据不能为空"}


# 生html详细报告
def detail_report(diff_data: List[DocDataObj], file_paths: list):
    start_time = datetime.datetime.now()
    if diff_data:
        write_log(" 正在获取word文件或者pdf文件的内容列表\n")
        # doc转docx
        word_pdf_content = get_word_pdf_content(file_paths)

        try:
            write_log(" 正在操作word文件或者pdf文件内容替换\n")
            # word文件或者pdf文件内容替换, 参数1 报告的id, 2 word文件或者pdf文件的内容列表
            word_pdf_content = word_pdf_content_replace(diff_data, word_pdf_content)
        except:
            error_log()

        try:
            write_log(" 正在生成html文件,保存html路径到数据库\n")
            # 生成html文件,保存html路径到数据库 返回html文件路径列表
            # 参数 1 报告的id, 2 保存html文件的根路径, 3 word文件或者pdf文件的内容列表, 4 操作数据库对象
            html_file_paths = generate_html_file(word_pdf_content)
            if not html_file_paths and len(html_file_paths) == 0:
                return None
        except:
            error_log()
            return None

        write_log(" 生成html页面完毕" + str((datetime.datetime.now() - start_time).seconds) + ' 秒\n')
        return html_file_paths


async def word2Vec(item_data: Item_data):
    if not item_data:
        return {'msg': '主文件不能为空', 'code': 500}
    mongodb_obj.delete('word2Vec', {"reportId": item_data.reportId})
    source = item_data.sourceFile
    # 获取主文件内容
    source_contents = get_txt_content(source.get('filePath'), item_data.leastChar)
    if len(source_contents) == 0:
        return {'msg': '主文件内容不能为空', 'code': 500}
    index, tfidf, dictionary = similarity_word(source_contents)
    for file in item_data.fileItem:
        # 获取招标文件内容
        targets = get_txt_content(file.get('filePath'), item_data.leastChar)
        for target_str in targets:
            kw_vector = dictionary.doc2bow(seg_sentence(target_str))
            sim = index[tfidf[kw_vector]]
            for s in range(len(sim)):
                if item_data.sim <= sim[s]:
                    obj = {}
                    obj['reportId'] = item_data.reportId
                    obj['source_id'] = source.get('id')
                    obj['source'] = source_contents[s]
                    obj['target_id'] = file.get('id')
                    obj['target'] = target_str
                    obj['sim'] = float(sim[s])
                    obj['createTime'] = datetime.datetime.now()
                    mongodb_obj.insert_one('word2Vec', obj)
    return {'msg': '操作成功', 'code': 200}


# 异常日志
def error_log():
    with open(log_path + 'log.log', "a") as f:
        traceback.print_exc(file=f)


# doc文件转成docx, pdf转docx, flag为diff是文件对比调用,template是对模板文件调用,为html是生成html文件时调用
def to_docx(file_paths, flag):
    # linux环境下doc转docx
    # mongo_obj = MongoDBUtil()
    error_file_path = []
    if flag == "diff":
        file_path_list = []
        for file_path in file_paths:
            if os.path.exists(file_path):
                if file_path.endswith('.doc'):
                    docx_path = flag_docx(file_path)
                    if docx_path:
                        file_path = docx_path
                        file_path_list.append(file_path)
                        continue
                    try:
                        docx_file_path = thread_to_docx(file_path)
                        file_path = docx_file_path
                        file_path_list.append(file_path)
                    except:
                        doc_error()
                        write_log(" 正在删除转换异常文件" + str(file_path))
                        error_file_path.append(file_path)
                elif file_path.endswith('.pdf') or file_path.endswith('.PDF'):
                    docx_path = flag_docx(file_path)
                    if docx_path:
                        # new_file_name = os.abspath(file_path[:-5] + "v.docx")
                        # new_file_name = os.abspath(docx_path[:-5] + "v.docx")
                        # copyfile(docx_path, new_file_name)
                        file_path = docx_path
                        file_path_list.append(file_path)
                        continue
                    try:
                        docx_path = pdf_docx(file_path)
                        file_path = docx_path
                        file_path_list.append(file_path)
                    except:
                        write_log(" 正在删除转换异常文件" + str(file_path))
                        error_file_path.append(file_path)
                elif file_path.endswith('.docx'):
                    file_path_list.append(file_path)

        return file_path_list, error_file_path
    elif flag == "template":
        template_list = []
        for template in file_paths:
            # 判断文件是否存在
            if os.path.exists(template):
                if template.endswith('.doc'):
                    docx_path = flag_docx(template)
                    if docx_path:
                        template_list.append(docx_path)
                        continue
                    try:
                        docx_file_path = thread_to_docx(template)
                        template_list.append(docx_file_path)
                    except:
                        doc_error()
                        write_log("正在删除转换异常文件" + str(template))
                        error_file_path.append(template)
                elif template.endswith('.pdf') or template.endswith('.PDF'):
                    docx_path = flag_docx(template)
                    if docx_path:
                        template_list.append(docx_path)
                        continue
                    try:
                        docx_path = pdf_docx(template)
                        template_list.append(docx_path)
                    except:
                        write_log("正在删除转换异常文件" + str(template))
                        error_file_path.append(template)
                elif template.endswith('.docx'):
                    template_list.append(template)
                elif template.endswith('.xls') or template.endswith('.xlsx'):
                    template_list.append(template)
        return template_list, error_file_path
    elif flag == "html":
        file_path_list = []
        for file_path in file_paths:
            if os.path.exists(file_path):
                if file_path.endswith('.doc'):
                    # 判断该doc文件对应的docx是否存在
                    docx_path = flag_docx(file_path)
                    if docx_path:
                        file_path = docx_path
                        file_path_list.append(file_path)
                elif file_path.endswith('.pdf') or file_path.endswith('.PDF'):
                    docx_path = flag_docx(file_path)
                    if docx_path:
                        file_path = docx_path
                        file_path_list.append(file_path)
                elif file_path.endswith('.docx'):
                    file_path_list.append(file_path)
        return file_path_list, error_file_path


@func_set_timeout(240)
def thread_to_docx(file_path):
    write_log(file_path + " 文件正在转换中 ")
    # linux 下doc转docx
    index_start = file_path.rindex(os.sep)
    index_end = file_path.rindex('.')
    file_name = file_path[index_start + 1:index_end]
    outdir = file_path[:index_start]
    doc_convert_docx(file_path, outdir)
    # 获取新文件路径
    file_paths = outdir + os.sep + file_name + '.docx'
    return file_paths

    # window下doc转docx
    # pythoncom.CoInitialize()
    # word = wc.Dispatch('Word.Application')
    # print("开始处理文件名：" + file_path)
    # path = os.abspath(file_path)
    # doc = word.Documents.Open(path)
    # docxNamePath = os.abspath(path[:-4] + ".docx")
    # print('转换完成！' + docxNamePath)
    # doc.SaveAs(docxNamePath, 12, False, "", True, "", False, False, False, False)
    # doc.Close()
    # return docxNamePath


# pdf文件转docx
@func_set_timeout(800)
def pdf_docx(pdf_path: str):
    write_log(pdf_path + " 文件正在转换中")
    # docx文件名称
    docx_name = pdf_path.split('.')[0] + '.docx'
    cv = Converter(pdf_path)
    cv.convert(docx_name)
    cv.close()
    return docx_name


# 判断docx文件是否存在
def flag_docx(file_path: str):
    docx_path = file_path.split('.')[0] + '.docx'
    if os.path.exists(docx_path):
        return docx_path
    else:
        return None


# 日志跟中写入
def write_log(log: str):
    with open(log_path + 'log.log', "a") as f:
        f.write(str(datetime.datetime.now()) + " -- " + log + "\n")


def doc_convert_docx(file_path, outdir):
    # doc转docx
    subprocess.run(['soffice', '--headless', '--convert-to', 'docx',
                    '--outdir', outdir,
                    file_path])
    return outdir


# 如果doc转换失败,杀死soffice进程方法
def doc_error():
    subprocess.run('pkill soffice', shell=True)


# 相似度对比算法
def similar_juxtapose(file_list: List[File_data]):
    # 相似度总数 ,返回的数据列表,
    total_number = 0
    result_data = []
    for i in range(len(file_list)):
        if i == len(file_list) - 1:
            break
        global_content = file_list[i].content
        if not global_content or global_content[0] in '':
            continue
        index, tfidf, dictionary = similarity_word(global_content)
        for j in range(i + 1, len(file_list)):
            target_paragraphs = file_list[j].content
            if not target_paragraphs:
                continue
            result_list_height = 0
            for target_str in target_paragraphs:
                # 同理，用词典把搜索词也转换为稀疏向量
                kw_vector = dictionary.doc2bow(seg_sentence(target_str))
                # 相似的计算
                sim = index[tfidf[kw_vector]]
                for s in range(len(sim)):
                    if sim[s] >= 0.8:
                        doc_data_obj = DocDataObj()
                        doc_data_obj.sFile = global_content[s]
                        doc_data_obj.tFile = target_str
                        doc_data_obj.anchor = str(getHashCode(global_content[s]))
                        doc_data_obj.score = float(sim[s])
                        result_data.append(doc_data_obj)
                        result_list_height += 1

            total_number += result_list_height
    return result_data, total_number


# 获取word文件或者pdf文件的内容列表
def get_word_pdf_content(file_list: list):
    word_pdf_content = []
    for file in file_list:
        if os.path.exists(file):
            if file.endswith(".docx"):
                # 获取word文件中的内容
                try:
                    # source_word = docx.Document(file)
                    source_word = get_paragraphs_text(file)
                    for source_text_index, source_text in enumerate(source_word):
                        source_text = "<span>" + source_text.replace("<", "&lt;").replace(">", "&gt;") + "</span>\n"
                        source_word[source_text_index] = source_text
                    word_pdf_content.append(
                        {"source_content": source_word, "path": file})
                except:
                    traceback.print_exc()
                    error_log()
    return word_pdf_content


# word文件或者pdf文件内容替换, 参数1 报告的id, 2 word文件或者pdf文件的内容列表
def word_pdf_content_replace(diff_data: List[DocDataObj], word_pdf_content):
    try:
        if not len(word_pdf_content) == 2:
            return None
        for data in diff_data:
            source_content = data.sFile
            many_content = data.tFile
            for para_index, para in enumerate(word_pdf_content[0].get('source_content')):
                if source_content in para:
                    para = para.replace(source_content, '<span><font color="red" id="' + str(
                        data.anchor) + '">' + source_content + '</font></span>\n')
                    word_pdf_content[0].get('source_content')[para_index] = para
            for para_index, para in enumerate(word_pdf_content[1].get('source_content')):
                if many_content in para:
                    para = para.replace(source_content, '<span><font color="red" id="' + str(
                        data.anchor) + '">' + many_content + '</font></span>\n')
                    word_pdf_content[1].get('source_content')[para_index] = para
    except:
        error_log()
        traceback.print_exc()

    return word_pdf_content


# 生成html页面
def generate_html_file(word_pdf_content):
    # 保存word, 转html
    html_file_paths = []
    for word_pdf in word_pdf_content:
        write_log(" 正在生成" + word_pdf.get("path") + " 文件对应的html文件\n")
        file_name = word_pdf.get("path")[
                    word_pdf.get("path").rindex(os.sep) + 1:word_pdf.get("path").rindex(
                        '.')]
        # 生成html保存路径
        html_path = word_pdf.get("path")[:word_pdf.get("path").rindex('.')] + ".html"

        html_text = html_content % file_name + "".join(word_pdf.get("source_content")) + "</body></html>"

        with open(html_path, "w", encoding='utf-8') as f:
            f.write(html_text)
            f.close()

        if os.path.exists(html_path):
            html_file_paths.append(html_path)
        else:
            html_file_paths.append('')
        # 释放内存
        del html_text
        gc.collect()

    del word_pdf_content
    gc.collect()

    return html_file_paths
    # return True
